let Measure = (function () {

    function Measure(viewer) {
        this.viewer = viewer;
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
        this.isMeasuring = false;
        this.points = [];
        this.lines = [];
        this.lineId = 0;
        this.distance = 0;
    }

    Measure.prototype.measureDistance = function () {
        this.isMeasuring = true;
        for (let i = 0; i < this.lines.length; i++) {
            this.viewer.entities.removeById(this.lines[i])
        }
        this.points = [];
        this.lines = [];
        this.distance = 0;

        this.handler.setInputAction(e => {
            let cartesian = this.viewer.camera.pickEllipsoid(e.position, this.viewer.scene.globe.ellipsoid);
            if (cartesian && this.isMeasuring) {
                let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
                let lng = Cesium.Math.toDegrees(cartographic.longitude);
                let lat = Cesium.Math.toDegrees(cartographic.latitude);
                this.points.push([lng, lat]);
                this.showLine();
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        this.handler.setInputAction(e => {
            this.isMeasuring = false;
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    Measure.prototype.showLine = async function () {
        if (this.points.length < 2) {
            this.lineId++;
            let point = {
                id: this.lineId,
                position: Cesium.Cartesian3.fromDegrees(this.points[0][0], this.points[0][1]),
                point: {
                    pixelSize: 20,
                    color: Cesium.Color.fromCssColorString("#ffffff").withAlpha(0.8),
                    outlineColor: Cesium.Color.fromCssColorString("#0000ff").withAlpha(0.8),
                    outlineWidth: 3,
                    disableDepthTestDistance: Number.POSITIVE_INFINITY,
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                }
            };
            this.lines.push(this.lineId);

            this.viewer.entities.add(point);

            return;
        }

        let positions = [];
        let point1 = this.points[this.points.length - 2];
        let point2 = this.points[this.points.length - 1];
        positions.push(Cesium.Cartesian3.fromDegrees(point1[0], point1[1]));
        positions.push(Cesium.Cartesian3.fromDegrees(point2[0], point2[1]));

        this.lineId++;
        let line = {
            id: this.lineId,
            name: 'polyline',
            polyline: {
                positions: positions,
                width: 10.0,
                clampToGround: true, //clampToGround属性设置线是否贴地，默认为flase, 不贴地
                material: new Cesium.PolylineGlowMaterialProperty({
                    color: Cesium.Color.CHARTREUSE.withAlpha(0.5)
                }),
                depthFailMaterial: new Cesium.PolylineGlowMaterialProperty({
                    color: Cesium.Color.CHARTREUSE.withAlpha(0.5)
                })
            }
        };
        this.lines.push(this.lineId);

        // 计算贴地距离
        let surfaceDistance = await this.computentDistance(point1[0], point1[1], point2[0], point2[1]);
        console.info('贴地距离=', surfaceDistance)

        let from = turf.point([point1[0], point1[1]]);
        let to = turf.point([point2[0], point2[1]]);
        let options = { units: 'kilometers' };

        let distance = turf.distance(from, to, options);
        this.distance += distance;

        let unit = "千米";
        let txt;
        if (this.distance < 1) {
            distance = this.distance * 1000;
            unit = "米";
            txt = distance.toFixed(2) + unit;
        } else {
            distance = this.distance;
            txt = distance.toFixed(3) + unit;
        }

        this.lineId++;
        let label = {
            id: this.lineId,
            position: Cesium.Cartesian3.fromDegrees(point2[0], point2[1]),
            label: {
                text: txt,
                font: "24px",
                pixelOffset: new Cesium.Cartesian2(0, -25),
                disableDepthTestDistance: Number.POSITIVE_INFINITY,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            },
        };
        this.lines.push(this.lineId);

        this.lineId++;
        let point = {
            id: this.lineId,
            position: Cesium.Cartesian3.fromDegrees(point2[0], point2[1]),
            point: {
                pixelSize: 20,
                color: Cesium.Color.fromCssColorString("#ffffff").withAlpha(0.8),
                outlineColor: Cesium.Color.fromCssColorString("#0000ff").withAlpha(0.8),
                outlineWidth: 3,
                disableDepthTestDistance: Number.POSITIVE_INFINITY,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            }
        };
        this.lines.push(this.lineId);

        this.viewer.entities.add(line);
        this.viewer.entities.add(label);
        this.viewer.entities.add(point);
    }

    /**
     * 计算贴地距离
     */
    Measure.prototype.computentDistance = async function (lng1, lat1, lng2, lat2) {
        let height1 = await this.computentHeight(new Cesium.Cartographic.fromDegrees(lng1, lat1));
        let height2 = await this.computentHeight(new Cesium.Cartographic.fromDegrees(lng2, lat2));
        let position1 = new Cesium.Cartographic.fromDegrees(lng1, lat1, height1);
        let position2 = new Cesium.Cartographic.fromDegrees(lng2, lat2, height2);
        let geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(position1, position2);
        let surfaceDistance = geodesic.surfaceDistance;
        let points = [position1];
        for (let i = 100; i < surfaceDistance; i += 100) { // 分段采样
            let point = geodesic.interpolateUsingSurfaceDistance(i);
            points.push(point);
        }
        points.push(position2);
        let updatedPositions = await Cesium.sampleTerrain(this.viewer.terrainProvider, 12, points);
        let sum = 0.0;
        for (let i = 0; i < updatedPositions.length - 1; i++) {
            let geodesic = new Cesium.EllipsoidGeodesic();
            geodesic.setEndPoints(updatedPositions[i], updatedPositions[i + 1]);
            let surfaceDistance = geodesic.surfaceDistance;
            surfaceDistance = Math.sqrt(Math.pow(surfaceDistance, 2) + Math.pow(updatedPositions[i].height - updatedPositions[i + 1].height, 2));
            sum += surfaceDistance;
        }
        return sum;
    }

    /**
     * 根据经纬度计算地形高度
     */
    Measure.prototype.computentHeight = async function (position) {
        let terrainProvider = this.viewer.terrainProvider;
        let positions = [position];
        let result = await Cesium.sampleTerrainMostDetailed(terrainProvider, positions);
        return result[0].height;
    }

    return Measure;
})();
